//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <core.h>

//
// Condition
//
void DzCondition::UninterruptibleWait(DzMutex *pMutex)
{
    assert(pMutex);
    assert(pMutex->IsHeld() && pMutex->IsHeldOnce());

    bool_t bOriginalPreemption = DzDisablePreemption();
    WaiterReadyToUninterruptibleSleep();

    pMutex->UnlockBegin();
    DzRestorePreemption(bOriginalPreemption);

    pMutex->UnlockEnd();

    Schedule();

    pMutex->UninterruptibleLock();
}

void DzCondition::Wait(DzMutex *pMutex, WaitResult *pResult)
{
    assert(pMutex);
    assert(pMutex->IsHeld() && pMutex->IsHeldOnce());
    assert(pResult);

    bool_t bOriginalPreemption = DzDisablePreemption();
    WaiterReadyToSleep(pResult);
    if (WaitResult_OK != *pResult) {
        DzRestorePreemption(bOriginalPreemption);
        return;
    }
    pMutex->UnlockBegin();
    DzRestorePreemption(bOriginalPreemption);

    pMutex->UnlockEnd();

    Schedule();

    pMutex->UninterruptibleLock();

    if (ClearInterrupted()) {
        *pResult = WaitResult_Interrupted;
    }
    else {
        *pResult = WaitResult_OK;
    }
}

void DzCondition::TryUninterruptibleWait(
    DzMutex *pMutex, uint_t dueTicks,
    uint_t *pResidualTicks, WaitResult *pResult)
{
    assert(pMutex);
    assert(pMutex->IsHeld() && pMutex->IsHeldOnce());
    assert(0 < dueTicks);
    assert(pResult);

    DzTimer timer(dueTicks, ScheduleTimeout, GetCurrentThread());

    bool_t bOriginalPreemption = DzDisablePreemption();
    WaiterReadyToUninterruptibleSleep(&timer);
    pMutex->UnlockBegin();
    DzRestorePreemption(bOriginalPreemption);

    pMutex->UnlockEnd();

    Schedule();

    pMutex->UninterruptibleLock();

    if (timer.Due()) {
        if (NULL != pResidualTicks) {
            *pResidualTicks = 0;
        }
        *pResult = WaitResult_TimedOut;
    }
    else {
        if (NULL != pResidualTicks) {
            *pResidualTicks = timer.GetResidualTicks();
        }
        *pResult = WaitResult_OK;
    }
}

void DzCondition::TryWait(
    DzMutex *pMutex, uint_t dueTicks,
    uint_t *pResidualTicks, WaitResult *pResult)
{
    assert(pMutex);
    assert(pMutex->IsHeld() && pMutex->IsHeldOnce());
    assert(0 < dueTicks);
    assert(pResult);

    DzTimer timer(dueTicks, ScheduleTimeout, GetCurrentThread());

    bool_t bOriginalPreemption = DzDisablePreemption();
    WaiterReadyToSleep(&timer, pResult);
    if (WaitResult_OK != *pResult) {
        DzRestorePreemption(bOriginalPreemption);
        return;
    }
    pMutex->UnlockBegin();
    DzRestorePreemption(bOriginalPreemption);

    pMutex->UnlockEnd();

    Schedule();

    pMutex->UninterruptibleLock();

    if (ClearInterrupted()) {
        if (NULL != pResidualTicks) {
            *pResidualTicks = timer.GetResidualTicks();
        }
        *pResult = WaitResult_Interrupted;
    }
    else if (timer.Due()) {
        if (NULL != pResidualTicks) {
            *pResidualTicks = 0;
        }
        *pResult = WaitResult_TimedOut;
    }
    else {
        if (NULL != pResidualTicks) {
            *pResidualTicks = timer.GetResidualTicks();
        }
        *pResult = WaitResult_OK;
    }
}
